package me.zhengjie.timing.lift;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.agvSend.AgvSendService;
import me.zhengjie.nettydemo.lift.LiftStatusVo;
import me.zhengjie.nettydemo.mapper.LiftNettyMapper;
import me.zhengjie.nettydemo.nettty.LiftCenter;
import me.zhengjie.pojo.dto.NoticeAgvDto;
import me.zhengjie.pojo.entity.LiftTask;
import me.zhengjie.pojo.entity.LiftTaskHistory;
import me.zhengjie.pojo.entity.LiftWaitPoint;
import me.zhengjie.sqlservilce.LiftTaskHistoryService;
import me.zhengjie.sqlservilce.LiftTaskSqlService;
import me.zhengjie.sqlservilce.LiftWaitPointService;
import me.zhengjie.util.state.LiftTaskStatus;
import me.zhengjie.util.state.TaskType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;


@Slf4j
@Component
@RequiredArgsConstructor
public class LiftStatusMachine {
    private static final Logger liftLog = LoggerFactory.getLogger("liftTask");

    private final LiftTaskSqlService liftTaskService;

    private final AgvSendService agvSendService;

    private final LiftWaitPointService liftWaitPointService;

    private final LiftTaskHistoryService liftTaskHistoryService;

    private final LiftNettyMapper liftNettyMapper;

    private final LiftCenter liftCenter;

    // 电梯任务状态机
    //定时任务
    @Transactional
//    @Scheduled(fixedDelay = 1000)
    public void startLiftTask() {
        List<LiftTask> liftTaskList = liftTaskService.selectAll();
        for (LiftTask liftTask : liftTaskList) {
            Integer id = liftTask.getId();
            String taskCode = liftTask.getTaskCode();
            String liftCode = liftTask.getLiftCode();
            String status = liftTask.getStatus();
            String startFloor = liftTask.getStartFloor();
            Integer startFloorInt = Integer.valueOf(startFloor);
            String endFloor = liftTask.getEndFloor();
            Integer endFloorInt = Integer.valueOf(endFloor);
            String liftStorage = liftTask.getLiftStorage();
            LocalDateTime updateTime = liftTask.getUpdateTime();
            if (TaskType.NEW_FLOOR.equals(taskCode)) {
                try {
                    //todo 电梯回复报文都为模拟，已电梯文档为准
                    switch (status) {
                        case "0":
                            LiftStatusVo liftInfo1 = liftNettyMapper.findLiftInfo(liftCode);
                            int currentFloor = liftInfo1.getCurrentFloor();
                            if (currentFloor == startFloorInt){
                                //电梯在起始楼层，发送开门指令
                                Integer liftNettyMapper0penDoor = liftNettyMapper.get0penDoor(liftCode);
                                if (liftNettyMapper0penDoor !=null && liftNettyMapper0penDoor == 1){
                                    boolean b = liftTaskService.updateStatus(id, LiftTaskStatus.RECEIVED_CALL.getCode());
                                    if (!b){
                                        liftLog.error("修改电梯任务状态为1，数据库异常，回滚");
                                        throw new RuntimeException("修改电梯任务状态为1，数据库异常，回滚");
                                    }
                                }else {
                                    boolean b = liftCenter.openDoor(liftCode);
                                    if (!b){
                                        liftLog.error("状态1，发送开门指令失败");
                                        throw new RuntimeException("状态1，发送开门指令失败");
                                    }
                                }
                            }else {
                                //状态为0{任务已生成，未执行，下发呼叫电梯指令}
                                liftLog.info("目前任务状态：任务已生成，未执行，任务状态:{}", liftTask);
                                //呼叫电梯成功，修改状态
                                Integer storageCallLiftFrame = liftNettyMapper.getStorageCallLiftFrame(liftCode);
                                if (storageCallLiftFrame !=null && storageCallLiftFrame == 1) {
                                    boolean b = liftTaskService.updateStatus(id, LiftTaskStatus.RECEIVED_CALL.getCode());
                                    if (!b){
                                        liftLog.error("修改电梯任务状态为1，数据库异常，回滚");
                                        throw new RuntimeException("修改电梯任务状态为1，数据库异常，回滚");
                                    }
                                }else {
                                    //呼叫电梯
                                    boolean b = liftCenter.callLift(liftCode, startFloorInt);
                                    if (!b){
                                        liftLog.error("发送呼叫电梯指令失败");
                                        throw new RuntimeException("发送呼叫电梯指令失败");
                                    }
                                }
                            }
                            break;
                        case "1":
                            //状态为1{电梯已收到呼叫指令，判断电梯是否到达目标楼层，并开门到位}
                            LiftStatusVo liftInfo = liftNettyMapper.findLiftInfo(liftCode);
                            if (liftInfo !=null){
                                if (liftInfo.getCurrentFloor() == startFloorInt && liftInfo.getLiftDoorStatus() == 2){
                                    boolean b = liftTaskService.updateStatus(id, LiftTaskStatus.ARRIVE_START_FLOOR_AND_OPEN_DOOR.getCode());
                                    if (!b){
                                        liftLog.error("修改电梯任务状态为2，数据库异常，回滚");
                                        throw new RuntimeException("修改电梯任务状态为2，数据库异常，回滚");
                                    }
                                }
                            }
                            //判断1分钟未执行到位回滚
                            LocalDateTime now = LocalDateTime.now();
                            long seconds = Duration.between(updateTime, now).getSeconds();
                            if (seconds >60){
                                liftLog.info("一分钟后电梯未到达其实楼层并开门到位，数据回滚到0");
                                boolean b = liftTaskService.updateStatus(id, LiftTaskStatus.TASK_UNEXECUTED.getCode());
                                if (!b){
                                    liftLog.error("修改电梯任务状态为0，数据库异常，回滚");
                                    throw new RuntimeException("修改电梯任务状态为0，数据库异常，回滚");
                                }
                            }
                            break;
                        case "2":
                            //状态为2{电梯到达起始楼层并开门到位，通知AGV进入电梯储位}
                            //下发AGV进入电梯储位，执行，进电梯储位
                            NoticeAgvDto noticeAgvDto = new NoticeAgvDto();
                            noticeAgvDto.setEqptCode(liftCode);
                            noticeAgvDto.setTaskCode(taskCode);
                            //todo 进入电梯，枚举不清楚
                            noticeAgvDto.setActionStatus("3");
                            noticeAgvDto.setSiteCode(liftStorage);
                            boolean b3 = agvSendService.noticeAgv(noticeAgvDto);
                            if (b3){
                                liftLog.info("通知AGV进入电梯储位成功，修改状态");
                                //通知AGV进入电梯储位，修改状态
                                boolean b1 = liftTaskService.updateStatus(id, LiftTaskStatus.GET_ORDER_ENTER_LIFT.getCode());
                                if (!b1){
                                    liftLog.error("修改电梯任务状态为3，数据库异常，回滚");
                                    throw new RuntimeException("修改电梯任务状态为3，数据库异常，回滚");
                                }
                            }
                            break;
                        case "3":
                            //agv进入电梯储位，上报给WCS
                            break;
                        case "4":
                            //agv是；上报到达电梯储位，下发关门至某层指令
                            Integer storageCloseDoorGoFloorFrame = liftNettyMapper.get0penDoor(liftCode);
                            if (storageCloseDoorGoFloorFrame != null && storageCloseDoorGoFloorFrame == 1){
                                //修改状态，关门至某层指令下发成功
                                boolean b1 = liftTaskService.updateStatus(id, LiftTaskStatus.CLOSE_DOOR_TO_END_FLOOR.getCode());
                                if (!b1){
                                    liftLog.error("修改电梯任务状态为5，数据库异常，回滚");
                                    throw new RuntimeException("修改电梯任务状态为5，数据库异常，回滚");
                                }
                            }else {
                                //下发关门至某层指令
                                boolean b = liftCenter.closeDoorAndGoToFloor(liftCode, endFloorInt);
                                if (!b){
                                    liftLog.error("发送关门至某层指令失败");
                                    throw new RuntimeException("发送关门至某层指令失败");
                                }
                            }
                            break;
                        case "5":
                            //关门至某层指令，判断电梯是否到达终点楼层并开门到位
                            LiftStatusVo liftInfo2 = liftNettyMapper.findLiftInfo(liftCode);
                            if (liftInfo2 !=null){
                                if (liftInfo2.getCurrentFloor() == endFloorInt && liftInfo2.getLiftDoorStatus() == 2){
                                    //电梯到达终点楼层并开门到位
                                    boolean b1 = liftTaskService.updateStatus(id, LiftTaskStatus.ARRIVE_END_FLOOR_AND_OPEN_DOOR.getCode());
                                    if (!b1){
                                        liftLog.error("修改电梯任务状态为6，数据库异常，回滚");
                                        throw new RuntimeException("修改电梯任务状态为5，数据库异常，回滚");
                                    }
                                }
                            }
                            LocalDateTime now1 = LocalDateTime.now();
                            long seconds1 = Duration.between(updateTime, now1).getSeconds();
                            if (seconds1 >60){
                                liftLog.info("一分钟后电梯未到达终点楼层并开门到位，数据回滚到0");
                                boolean b = liftTaskService.updateStatus(id, LiftTaskStatus.ARRIVE_STORAGE_POINT.getCode());
                                if (!b){
                                    liftLog.error("修改电梯任务状态为0，数据库异常，回滚");
                                    throw new RuntimeException("修改电梯任务状态为0，数据库异常，回滚");
                                }
                            }
                            break;
                        case "6":
                            //电梯到达终点楼层并开门到位，通知AGV离开电梯
                            //下发AGV离开电梯储位，执行，离开电梯储位
                            NoticeAgvDto noticeAgvDto1 = new NoticeAgvDto();
                            noticeAgvDto1.setEqptCode(liftCode);
                            noticeAgvDto1.setTaskCode(taskCode);
                            //todo 离开电梯，枚举不清楚
                            noticeAgvDto1.setActionStatus("4");
                            noticeAgvDto1.setSiteCode(liftStorage);
                            boolean b2 = agvSendService.noticeAgv(noticeAgvDto1);
                            if (b2){
                                liftLog.info("通知AGV进入电梯储位成功，修改状态");
                                //通知AGV进入电梯储位，修改状态
                                boolean b1 = liftTaskService.updateStatus(id, LiftTaskStatus.GET_ORDER_LEAVE_LIFT.getCode());
                                if (!b1){
                                    liftLog.error("修改电梯任务状态为7，数据库异常，回滚");
                                    throw new RuntimeException("修改电梯任务状态为3，数据库异常，回滚");
                                }
                            }
                            break;
                        case "7":
                            //通知AGV离开电梯指令，上报WCS离开电梯
                            break;
                        case "8":
                            //agv离开电梯储位，判断电梯是否要关门，同楼层有任务不用关门，删除任务，移到历史表
                            List<LiftWaitPoint> liftWaitPointList = liftWaitPointService.selectFloor(endFloor);
                            if (liftWaitPointList.isEmpty()){
                                Integer storageCloseDoorFrame = liftNettyMapper.getStorageCloseDoorFrame(liftCode);
                                if (storageCloseDoorFrame !=null && storageCloseDoorFrame ==1 ){
                                    LiftTaskHistory liftTaskHistory = new LiftTaskHistory();
                                    BeanUtils.copyProperties(liftTask,liftTaskHistory);
                                    liftTaskHistory.setId(null);
                                    boolean b = liftTaskHistoryService.insertLiftTask(liftTaskHistory);
                                    if (!b){
                                        liftLog.error("将任务添加到历史表失败，数据回滚");
                                        throw new RuntimeException("将任务添加到历史表失败，数据回滚");
                                    }
                                    //删除电梯任务
                                    boolean b1 = liftTaskService.deleteId(id);
                                    if (!b1){
                                        liftLog.error("删除任务失败");
                                        throw new RuntimeException("删除任务失败");
                                    }
                                }else {
                                    //关门
                                    boolean b = liftCenter.closeDoor(liftCode);
                                    if (!b){
                                        liftLog.error("发送关门指令失败");
                                        throw new RuntimeException("发送关门指令失败");
                                    }
                                }
                            }else {
                                LiftTaskHistory liftTaskHistory = new LiftTaskHistory();
                                BeanUtils.copyProperties(liftTask,liftTaskHistory);
                                liftTaskHistory.setId(null);
                                boolean b = liftTaskHistoryService.insertLiftTask(liftTaskHistory);
                                if (!b){
                                    liftLog.error("将任务添加到历史表失败，数据回滚");
                                    throw new RuntimeException("将任务添加到历史表失败，数据回滚");
                                }
                                //删除电梯任务
                                boolean b1 = liftTaskService.deleteId(id);
                                if (!b1){
                                    liftLog.error("删除任务失败");
                                    throw new RuntimeException("删除任务失败");
                                }
                            }
                            break;
//                    case "9":
//                        //通知电梯关门。当前楼层有任务不关门
//                        break;
                        default:
                            break;
                    }
                } catch (Exception e) {
                    LiftStatusMachine.liftLog.error("catch报错日志", e);
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                }
            }
        }


    }
}